圖:“Rust 的吉祥物 Ferris the Crab 擁有強壯的肌肉,正扛著一堆木箱,在崎嶇的山路上行走”,gemini-2.5-flash-preview,2025年09月16日。
Rust 是門「重編譯,輕執行」的程式語言,也相對年輕,必然也都看著各前輩們負重前行,所以 Rust 一誕生就自帶了強壯穩定的骨架,好讓它能夠讓編寫出來程式碼在編譯階段就做完檢查、優化等,產生高效能、安全的軟體。如果沒有一個穩定的骨架,幾乎是難以做到既要、又要、還要的。
學習一門新的語言,不免俗的一定要到它的官方網站查看,Rust 官方網站,這裡有你一切需要的標準答案!絕大部分工程面的問題,你都可以在這邊找到答案,至少能解決90%以上的問題,剩下的10%問題,也有可能不是軟體工程的問題,而是你老闆的問題 XD(誤。這當然是句玩笑話!
但,若遇到這樣的情景,Rust 的骨架體系是能夠很明確地、不斷地提醒你「行不通」。換句話來說,是不是就在更早的階段,甚至是想法嚐鮮、實驗階段就提醒你是不是在思考這類問題時,方向完全錯了!某程度來說,不也挺浪漫的嗎?XD
以下表格我也統整了常見,不見得常用的文檔與經驗分享:
網站 | 解釋 |
---|---|
The Rust Programming Language | 這就是 Rust 的聖經,語法該如何寫都在這,標準課本。 |
Rust By Example | 透過範例學習,不害怕錯中學,就從這邊開始吧。 |
The Rust Standard Library | 標注函式庫的技術說明文件(例如:Vec, HashMap 等等),就是字典。 |
The Rust Edition Guide | 詳細說明了每個版本帶來了哪些變化,以及如何將專案從舊版本遷移到新版本,或許到超大型專案才會願意查看吧(誤。 |
The Cargo Book | Cargo的完整使用手冊,但通常 cargo --help 就好了啦。 |
The rustdoc book | 教你如何讓你的程式碼附帶技術文件,往專業化和發佈 crate 的時候,還是照著規則描述,會好管理很多。 |
The rustc book | 編譯器之書,當被編譯器支配的恐懼來到極點後,就會默默打開,然後討厭它,接受它,喜歡它,成為它。 |
Rust error codes index | 編譯時期的錯誤列表,console 看不懂就上來看解釋吧!但通常 rustc --explain E0308 就好了啦。 |
地基打得穩,房子才蓋得高。必備的工具們哪能不介紹!
rustc
:Rust 的核心編譯器,由 Rust 編寫,就是那位「嚴師」。不過實際上 rustc 並不會將 Rust 程式碼直接編譯成機械碼,而是會編譯成 LLVM IR,LLVM 會自動將其編譯成機械碼後,即可執行。正因如此,你會聽到有人說:“Rust 是由 Rust 編寫,但離不開 C++”。rustup
:Rust 工具鏈(Toolchain)大總管,讓你輕鬆安裝、更新,甚至切換不同版本的 Rust。cargo
:Rust 專案管理套件,但我願稱它為「骨架」。它就是你開發生命週期中可以說唯一要打交道的工具,從專案建立、編譯、套件管理都它統一搞定。rust-analyzer
:這是 Rust 的 LSP(Language Server Protocol),功能強大,推薦安裝。程式碼自動補全、錯誤提示等等樣樣精通的精靈助手,它讓你在那位「嚴師」還沒罵你之前,就先提醒你。唯一要注意的是因為是 LSP,在背景會自動執行,會相當耗費 CPU 資源,可在 IDE 中自行關閉或暫停。Rustc 編譯器與 Cargo 專案管理版本查看,以下為本系列鐵人賽中所使用的版本。不用過度擔心版本問題! 根據我的開發經驗,Rustc 和 Cargo 的版本迭代對日常開發的實質影響很有限。
rustc --version # rustc 1.89.0 (29483883e 2025-08-04)
cargo --version # cargo 1.89.0 (c24e10642 2025-06-23)
# 建立一個名為 "my_app" 的新專案
cargo new my_app
cd my_app
# 專案結構解析(一):默認
my_app/
├── Cargo.toml # 專案配置檔案
├── src/ # 原始碼目錄
│ └── main.rs # 主程式檔案
└── .gitignore # Git 忽略檔案(自動建立)
# 添加 serde 套件(用於 JSON 處理)
cargo add serde
# 添加帶有功能的套件
cargo add serde --features derive
# 添加特定版本
cargo add rand@0.8
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
在程式碼中使用新添加的套件:(趕進度了,一開始寫就該站在巨人的肩膀上!)
// 引入 serde 庫的 Serialize 和 Deserialize 特徵
// 用於 JSON 序列化和反序列化
use serde::{Deserialize, Serialize};
// 定義 Person 結構體
// 使用 Serialize, Deserialize 特徵來支援 JSON 序列化
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Person {
name: String,
age: u32,
money: f64,
}
// Person 結構體的實作區塊
impl Person {
// 建構函數(關聯函數)
// 建構函數 - 用於創建新的 Person 實例
pub fn new(name: String, age: u32, money: f64) -> Self {
Person { name, age, money }
}
// 取得金錢的函數
pub fn get_money(&self) -> f64 {
self.money
}
}
// 計算總金錢的函數:累加每個人的金錢並返回總和
fn sum_money(people: &[Person]) -> f64 {
let mut total = 0.0;
for person in people {
total += person.get_money();
}
total
}
fn main() {
// 創建帶有金錢的 Person 結構體
let alice = Person::new("Alice".to_string(), 30, 100.50);
let bob = Person::new("Bob".to_string(), 25, 75.25);
let charlie = Person::new("Charlie".to_string(), 35, 200.00);
// 創建個人巨集
let people = vec![alice, bob, charlie];
// 計算總金額
let total_money = sum_money(&people);
println!("所有人的總金額:${:.2}", total_money);
// 印出每個個人的金額
for person in &people {
println!("{} 擁有 ${:.2}", person.name, person.get_money());
}
// 印出 JSON 格式
println!("\n=== JSON 格式 ===");
for person in &people {
let json = serde_json::to_string(person).unwrap();
println!("{}", json);
}
}
Cargo 核心三劍客:cargo check
、cargo build
與 cargo run
,Rust 開發者下意識的動作。口訣就是:cargo check
查語法、cargo run
看效果、cargo build
伸懶腰。以下表格說明了功能:
指令 | 執行檔 | 功能 |
---|---|---|
cargo check |
無 | 編譯器各種檢查,會產生中間檔案,故第二次僅檢查有更動的程式碼(build 與 run 皆是) |
cargo run |
有+執行 | 編譯爲可執行檔後,自動執行 |
cargo build |
有 | 編譯為可執行檔 |
以下表格說明 build 與 run 常見指令,以 build 為範例,但 run 共用指令參數。
指令 | 功能 |
---|---|
cargo build |
編譯專案,產生未經優化的開發版本執行檔 |
cargo build --release |
編譯專案,產生完全優化的發佈版本執行檔 |
cargo build --bin <name> |
僅編譯 src/bin 下 <name> 檔案成執行檔 |
cargo build --example <name> |
僅編譯 examples 下 <name> 範例檔案成執行檔 |
在 src/main.rs
的結尾添加測試:
#[cfg(test)]
mod tests {
use super::*;
// 測試 Person 結構體的 get_money 方法
#[test]
fn test_get_money() {
let person = Person::new("Alice".to_string(), 30, 100.50);
assert_eq!(person.get_money(), 100.50);
}
// 測試 sum_money 函數
#[test]
fn test_sum_money() {
let people = vec![
Person::new("Alice".to_string(), 30, 100.50),
Person::new("Bob".to_string(), 25, 75.25),
Person::new("Charlie".to_string(), 35, 200.00),
];
assert_eq!(sum_money(&people), 375.75);
}
}
# 運行所有測試
cargo test
# 運行特定測試
cargo test test_get_money
cargo test test_sum_money
# 運行並顯示詳細輸出
cargo test -- --nocapture
指令執行 cargo test
後,你應該會看到類似輸出:(都...ok,一日成就達成)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
Running unittests src/main.rs (target/debug/deps/cargo_tutorial-f11451fb6a32d6c5)
running 2 tests
test tests::test_get_money ... ok
test tests::test_sum_money ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s